package com.atguigu.crowd.mvc.config;

import com.atguigu.crowd.constant.CrowdConstant;
import com.atguigu.crowd.exception.LoginAcctAlreadyInUseException;
import com.atguigu.crowd.exception.LoginAcctAlreadyInUseForUpdateException;
import com.atguigu.crowd.exception.LoginFailedException;
import com.atguigu.crowd.util.CrowdUtil;
import com.atguigu.crowd.util.ResultEntity;
import com.google.gson.Gson;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//表示当前类是一个基于注解的异常处理器类
@ControllerAdvice
public class CrowdExceptionResolver {

//    将一个具体的异常类型和方法关联起来
//    如果项目抛出LoginFailedException异常则被此方法捕获
    @ExceptionHandler(value = LoginFailedException.class)
    public ModelAndView resolveNullPointException(
            LoginFailedException exception,
            HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse
    ) throws IOException {
        return commonResolve("admin-login",exception,httpServletRequest,httpServletResponse);
    }

//    这里服务器其实是报DuplicateKeyException这个异常。是由于数据库中唯一约束触发的异常，但是所有的DuplicateKeyException异常不一定是登录账号被使用，后面还有可能是修改其它表重复了唯一约束的属性。
//    所以我们自己定义了一个账号被使用异常类，在adminMapper.insert(admin);中如果检测到有这个异常肯定是账号名在数据库中已经存在了才抛出来的
//    我们只要去try catch :adminMapper.insert这个方法，instanceof判断异常异常类型是DuplicateKeyException，我们就抛出LoginAcctAlreadyInUseException异常，这里就会被捕获
    @ExceptionHandler(value = LoginAcctAlreadyInUseException.class)
    public ModelAndView resolveLoginAcctAlreadyInUseException(
            LoginAcctAlreadyInUseException exception,
            HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse
    ) throws IOException {
        return commonResolve("admin-add",exception,httpServletRequest,httpServletResponse);
    }

    @ExceptionHandler(value = LoginAcctAlreadyInUseForUpdateException.class)
    public ModelAndView resolveLoginAcctAlreadyInUseException(
            LoginAcctAlreadyInUseForUpdateException exception,
            HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse
    ) throws IOException {
        return commonResolve("system-error",exception,httpServletRequest,httpServletResponse);
    }

    private   ModelAndView commonResolve(
            String viewName,
            Exception exception,
            HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse
    )throws IOException {
//        如果是ajax请求则返回json
        if(CrowdUtil.judgeRequestType(httpServletRequest)){
//            先创建一个返回的信息对象
            ResultEntity<Object> failed = ResultEntity.failed(exception.getMessage());
//            将它转换为json格式
            Gson gson = new Gson();
            String json = gson.toJson(failed);
//            使用原生方式写回浏览器
            httpServletResponse.getWriter().write(json);
            return null;
        }
//        如果是普通请求返回视图
        ModelAndView modelAndView = new ModelAndView();
//        这里把异常存到request域中，使用${requestScope.exception.message}就可以取到
        modelAndView.addObject(CrowdConstant.ATTR_NAME_EXCEPTION,exception);
        modelAndView.setViewName(viewName);
        return modelAndView;

    }
}
